// Joi 模块中文API封装 - 用于数据验证
let Joi;
try {
  // 尝试导入Joi库
  Joi = require('joi');
} catch (e) {
  console.warn('警告: 未安装 joi 库，请运行 "npm install joi" 来安装');
}

/**
 * 验证Joi库是否已安装
 * @returns {boolean} 库是否可用
 */
function 验证Joi库() {
  if (!Joi) {
    throw new Error('未安装 joi 库，请运行 "npm install joi" 来安装');
  }
  return true;
}

/**
 * 创建新的验证模式
 * @param {*} 类型 - 初始类型或模式
 * @returns {Object} Joi验证器
 */
function 创建验证模式(类型) {
  验证Joi库();
  return Joi.compile(类型);
}

/**
 * 创建字符串验证器
 * @returns {Object} Joi字符串验证器
 */
function 字符串() {
  验证Joi库();
  return Joi.string();
}

/**
 * 创建数字验证器
 * @returns {Object} Joi数字验证器
 */
function 数字() {
  验证Joi库();
  return Joi.number();
}

/**
 * 创建布尔值验证器
 * @returns {Object} Joi布尔值验证器
 */
function 布尔值() {
  验证Joi库();
  return Joi.boolean();
}

/**
 * 创建日期验证器
 * @returns {Object} Joi日期验证器
 */
function 日期() {
  验证Joi库();
  return Joi.date();
}

/**
 * 创建数组验证器
 * @param {*} 元素模式 - 数组元素的验证模式
 * @returns {Object} Joi数组验证器
 */
function 数组(元素模式) {
  验证Joi库();
  return Joi.array().items(元素模式);
}

/**
 * 创建对象验证器
 * @param {Object} 模式 - 对象字段的验证模式
 * @returns {Object} Joi对象验证器
 */
function 对象(模式) {
  验证Joi库();
  return Joi.object(模式);
}

/**
 * 创建二进制数据验证器
 * @returns {Object} Joi二进制数据验证器
 */
function 二进制() {
  验证Joi库();
  return Joi.binary();
}

/**
 * 创建函数验证器
 * @returns {Object} Joi函数验证器
 */
function 函数() {
  验证Joi库();
  return Joi.function();
}

/**
 * 创建符号验证器
 * @returns {Object} Joi符号验证器
 */
function 符号() {
  验证Joi库();
  return Joi.symbol();
}

/**
 * 创建链接对象验证器
 * @returns {Object} Joi链接对象验证器
 */
function 链接() {
  验证Joi库();
  return Joi.link();
}

/**
 * 创建替代验证器
 * @param {Array} 替代选项 - 替代验证选项数组
 * @returns {Object} Joi替代验证器
 */
function 替代(替代选项) {
  验证Joi库();
  return Joi.alternatives(替代选项);
}

/**
 * 创建任何类型验证器
 * @returns {Object} Joi任何类型验证器
 */
function 任何() {
  验证Joi库();
  return Joi.any();
}

/**
 * 验证数据
 * @param {*} 数据 - 要验证的数据
 * @param {Object} 模式 - 验证模式
 * @param {Object} 选项 - 验证选项
 * @returns {Object} 验证结果
 */
function 验证(数据, 模式, 选项 = {}) {
  验证Joi库();
  return Joi.validate(数据, 模式, 选项);
}

/**
 * 异步验证数据
 * @param {*} 数据 - 要验证的数据
 * @param {Object} 模式 - 验证模式
 * @param {Object} 选项 - 验证选项
 * @returns {Promise} 验证结果Promise
 */
async function 异步验证(数据, 模式, 选项 = {}) {
  验证Joi库();
  try {
    const 结果 = await Joi.validate(数据, 模式, { ...选项, abortEarly: false });
    return { 错误: null, 值: 结果 };
  } catch (错误) {
    return { 错误, 值: null };
  }
}

/**
 * 创建严格验证模式
 * @param {*} 类型 - 验证类型
 * @returns {Object} 严格验证器
 */
function 严格(类型) {
  验证Joi库();
  return Joi.strict(类型);
}

/**
 * 创建当型验证器
 * @param {*} 条件 - 条件表达式
 * @param {*} 则 - 条件为真时的验证器
 * @param {*} 否则 - 条件为假时的验证器
 * @returns {Object} 当型验证器
 */
function 当(条件, 则, 否则) {
  验证Joi库();
  return Joi.when(条件, { is: 则, then: 否则 });
}

/**
 * 创建正则表达式验证器
 * @param {RegExp} 正则表达式 - 用于验证的正则表达式
 * @returns {Object} Joi字符串验证器
 */
function 正则表达式(正则表达式) {
  验证Joi库();
  return Joi.string().pattern(正则表达式);
}

/**
 * 创建必填验证器
 * @param {*} 类型 - 验证类型
 * @param {string} 错误消息 - 自定义错误消息
 * @returns {Object} 必填验证器
 */
function 必填(类型, 错误消息) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.required(错误消息);
}

/**
 * 创建可选验证器
 * @param {*} 类型 - 验证类型
 * @returns {Object} 可选验证器
 */
function 可选(类型) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.optional();
}

/**
 * 创建空值验证器
 * @param {*} 类型 - 验证类型
 * @returns {Object} 允许空值的验证器
 */
function 允许空(类型) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.empty();
}

/**
 * 创建长度验证器
 * @param {*} 类型 - 验证类型
 * @param {number} 长度 - 长度值
 * @returns {Object} 长度验证器
 */
function 长度(类型, 长度) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.length(长度);
}

/**
 * 创建最小值验证器
 * @param {*} 类型 - 验证类型
 * @param {number} 最小值 - 最小值
 * @returns {Object} 最小值验证器
 */
function 最小值(类型, 最小值) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.min(最小值);
}

/**
 * 创建最大值验证器
 * @param {*} 类型 - 验证类型
 * @param {number} 最大值 - 最大值
 * @returns {Object} 最大值验证器
 */
function 最大值(类型, 最大值) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.max(最大值);
}

/**
 * 创建范围验证器
 * @param {*} 类型 - 验证类型
 * @param {number} 最小值 - 最小值
 * @param {number} 最大值 - 最大值
 * @returns {Object} 范围验证器
 */
function 范围(类型, 最小值, 最大值) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.min(最小值).max(最大值);
}

/**
 * 创建枚举验证器
 * @param {*} 类型 - 验证类型
 * @param {Array} 允许的值 - 允许的值数组
 * @returns {Object} 枚举验证器
 */
function 枚举(类型, 允许的值) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.valid(...允许的值);
}

/**
 * 创建排除验证器
 * @param {*} 类型 - 验证类型
 * @param {Array} 排除的值 - 排除的值数组
 * @returns {Object} 排除验证器
 */
function 排除(类型, 排除的值) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.invalid(...排除的值);
}

/**
 * 创建邮箱验证器
 * @returns {Object} 邮箱验证器
 */
function 邮箱() {
  验证Joi库();
  return Joi.string().email();
}

/**
 * 创建URL验证器
 * @returns {Object} URL验证器
 */
function URL() {
  验证Joi库();
  return Joi.string().uri();
}

/**
 * 创建UUID验证器
 * @param {string} 版本 - UUID版本
 * @returns {Object} UUID验证器
 */
function UUID(版本) {
  验证Joi库();
  return Joi.string().uuid({ version });
}

/**
 * 创建IP地址验证器
 * @param {string} 版本 - IP版本 ('ipv4', 'ipv6')
 * @returns {Object} IP地址验证器
 */
function IP地址(版本) {
  验证Joi库();
  return Joi.string().ip({ version });
}

/**
 * 创建手机号验证器（中国大陆）
 * @returns {Object} 手机号验证器
 */
function 手机号() {
  验证Joi库();
  return Joi.string().pattern(/^1[3-9]\d{9}$/);
}

/**
 * 创建身份证号验证器（中国大陆）
 * @returns {Object} 身份证号验证器
 */
function 身份证号() {
  验证Joi库();
  return Joi.string().pattern(/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/);
}

/**
 * 创建用户名验证器
 * @param {Object} 选项 - 验证选项
 * @returns {Object} 用户名验证器
 */
function 用户名(选项 = {}) {
  验证Joi库();
  const { 最小长度 = 3, 最大长度 = 20 } = 选项;
  return Joi.string()
    .pattern(/^[a-zA-Z0-9_\u4e00-\u9fa5]+$/, '用户名')
    .min(最小长度)
    .max(最大长度)
    .message('用户名只能包含字母、数字、下划线和中文，长度在{min}-{max}个字符之间');
}

/**
 * 创建密码验证器
 * @param {Object} 选项 - 验证选项
 * @returns {Object} 密码验证器
 */
function 密码(选项 = {}) {
  验证Joi库();
  const { 最小长度 = 6, 包含小写字母 = true, 包含大写字母 = false, 包含数字 = true, 包含特殊字符 = false } = 选项;
  
  let 验证器 = Joi.string().min(最小长度);
  
  if (包含小写字母) {
    验证器 = 验证器.pattern(/[a-z]/, '小写字母');
  }
  
  if (包含大写字母) {
    验证器 = 验证器.pattern(/[A-Z]/, '大写字母');
  }
  
  if (包含数字) {
    验证器 = 验证器.pattern(/[0-9]/, '数字');
  }
  
  if (包含特殊字符) {
    验证器 = 验证器.pattern(/[!@#$%^&*(),.?":{}|<>]/, '特殊字符');
  }
  
  return 验证器;
}

/**
 * 创建自定义验证规则
 * @param {*} 类型 - 验证类型
 * @param {Function} 验证函数 - 自定义验证函数
 * @param {string} 错误消息 - 自定义错误消息
 * @returns {Object} 自定义验证器
 */
function 自定义规则(类型, 验证函数, 错误消息) {
  验证Joi库();
  const 验证器 = typeof 类型 === 'function' ? 类型() : 类型;
  return 验证器.custom(验证函数, 错误消息);
}

/**
 * 格式化验证错误信息
 * @param {Object} 错误 - Joi验证错误对象
 * @returns {Object} 格式化的错误信息
 */
function 格式化验证错误(错误) {
  if (!错误) return null;
  
  const 错误详情 = {};
  
  if (错误.details && Array.isArray(错误.details)) {
    错误.details.forEach(详情 => {
      const 路径 = 详情.path.join('.');
      错误详情[路径] = 详情.message;
    });
  }
  
  return {
    错误消息: 错误.message,
    错误详情
  };
}

/**
 * 合并多个验证模式
 * @param {Array} 模式数组 - 要合并的模式数组
 * @returns {Object} 合并后的模式
 */
function 合并模式(模式数组) {
  验证Joi库();
  return Joi.object().keys(Object.assign({}, ...模式数组));
}

/**
 * 创建部分验证模式（从现有模式中提取部分字段）
 * @param {Object} 原始模式 - 原始验证模式
 * @param {Array} 字段数组 - 要提取的字段数组
 * @returns {Object} 部分验证模式
 */
function 部分模式(原始模式, 字段数组) {
  验证Joi库();
  const 部分字段 = {};
  
  字段数组.forEach(字段 => {
    if (原始模式[字段]) {
      部分字段[字段] = 原始模式[字段];
    }
  });
  
  return Joi.object(部分字段);
}

/**
 * 复制验证模式
 * @param {Object} 模式 - 要复制的验证模式
 * @returns {Object} 复制的验证模式
 */
function 复制模式(模式) {
  验证Joi库();
  return Joi.compile(Joi.schema(模式));
}

// 导出API
module.exports = {
  // 核心功能
  创建验证模式,
  验证,
  异步验证,
  格式化验证错误,
  
  // 类型创建器
  字符串,
  数字,
  布尔值,
  日期,
  数组,
  对象,
  二进制,
  函数,
  符号,
  链接,
  替代,
  任何,
  严格,
  当,
  正则表达式,
  
  // 通用验证规则
  必填,
  可选,
  允许空,
  长度,
  最小值,
  最大值,
  范围,
  枚举,
  排除,
  自定义规则,
  
  // 常用验证器
  邮箱,
  URL,
  UUID,
  IP地址,
  手机号,
  身份证号,
  用户名,
  密码,
  
  // 模式操作
  合并模式,
  部分模式,
  复制模式,
  
  // 获取原始库引用
  获取原始Joi: () => Joi
};
